package com.xxx.mch.exception;

import com.netflix.hystrix.exception.HystrixRuntimeException;
import com.xxx.mch.utils.WrapMapper;
import com.xxx.mch.utils.Wrapper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 全局异常捕获，用户捕获在业务中未捕获到的异常， 增强用户体验
 *
 * @author FengHaixin
 * @description 一句话描述该文件的用途
 * @date 2018/6/2
 */
@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);


    @ExceptionHandler (Exception.class)
    public HttpEntity<Wrapper> handleException(Exception e)
    {
        LOGGER.error("捕获到全局异常，异常堆栈信息", e);
        if (e instanceof HystrixRuntimeException)
        {
            return new ResponseEntity<>(WrapMapper.error("系统内部异常：" + e.getCause().getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return new ResponseEntity<>(WrapMapper.error("系统内部异常：" + e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
    }


    @ExceptionHandler (DataIntegrityViolationException.class)
    public HttpEntity<Wrapper> handleSQLException(DataIntegrityViolationException e)
    {
        String errorMsg = e.getCause().getMessage();
        LOGGER.error("捕获到全局异常，异常堆栈信息", e);
        Pattern pattern = Pattern.compile("(?<=Field ['])\\w+(?=(' doesn't have a default value))");
        Matcher matcher = pattern.matcher(errorMsg);
        while (matcher.find())
        {
            String fieldName = matcher.group(0);
            if (StringUtils.isNotEmpty(fieldName))
            {
                return new ResponseEntity<>(WrapMapper.error(fieldName + "不能为空"), HttpStatus.INTERNAL_SERVER_ERROR);
            }
        }
        return new ResponseEntity<>(WrapMapper.error("系统内部异常：" + e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
    }


    @ExceptionHandler (BusinessException.class)
    public HttpEntity<Wrapper> businessException(Exception e)
    {
        LOGGER.error("捕获到业务异常信息", e);
        return new ResponseEntity<>(WrapMapper.error(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
    }


    @ExceptionHandler ({MethodArgumentNotValidException.class, BindException.class, MethodArgumentTypeMismatchException.class})
    public Wrapper methodArgumentNotValidException(Exception e)
    {
        LOGGER.error("接口请求参数异常", e);

        BindingResult bindingResult = getBindingResult(e);

        StringBuilder stringBuilder = new StringBuilder();

        if (bindingResult.hasErrors())
        {
            for (ObjectError error : bindingResult.getAllErrors())
            {
                stringBuilder.append(error.getDefaultMessage()).append("\n");
            }
            stringBuilder.setLength(stringBuilder.length() - 1);
        }

        return WrapMapper.error(stringBuilder.toString());
    }


    private BindingResult getBindingResult(Exception e)
    {
        BindingResult bindingResult = null;

        if (e instanceof MethodArgumentNotValidException)
        {

            bindingResult = ((MethodArgumentNotValidException)e).getBindingResult();
        }
        else if (e instanceof BindException)
        {
            bindingResult = ((BindException)e).getBindingResult();
        }

        return bindingResult;
    }

}
